#include <boost/lexical_cast.hpp>

#include "mpHashUtils.h"
#include "mpFileUtils.h"
#include "mpLog.h"

#include "mpHttpRequestFileContent.h"

namespace MP{
namespace HTTP{
namespace INTERNAL{


HttpRequestFileContent::HttpRequestFileContent(const std::string& filePath,
                                               std::size_t fileOffset,
                                               std::size_t sendContentSize)
    :HttpRequestFileContent(filePath,fileOffset,sendContentSize,"application/octet-stream")
{

}

HttpRequestFileContent::HttpRequestFileContent(const std::string& filePath,
                                               std::size_t fileOffset,
                                               std::size_t sendContentSize,
                                               const std::string & httpcontent_type)
    :_filePath(filePath),
      _fileOffset(fileOffset),
      _sendContentSize(sendContentSize),
      _sendContentTrueSize(0),
      _unreadSize(0)
{
    HttpRequestContent::setContentType(httpcontent_type);

    //        if(sendContentSize <= 0){
    //            throw HttpException("http request file content parameter error. sendContentSize :" + std::to_string(sendContentSize));
    //        }
    //        this->_filePath = filePath;
    //        this->_fileOffset = fileOffset;
    //        this->_sendContentSize = sendContentSize;
    //        //重新设置File信息后需要将sendContentTrueSize设置为空，并确保再下次调用getContentLength时会重新计算
    //        this->_sendContentTrueSize = 0;
}

std::string HttpRequestFileContent::getMd5()  {

    std::string md5;
    if(getContentLength() != 0){
        MP::HashUtils::file_md5_hex(_filePath,_fileOffset,getContentLength(),md5);
    }

    return md5;
}

std::size_t HttpRequestFileContent::getContentLength() {

    if(_sendContentTrueSize <= 0){

        std::size_t fileSize = MP::FileUtils::get_file_size(_filePath);

        //如果需发送的字节数（ _sendContentSize ） 有值( >0 ) 并且 偏移（_fileOffset） + 需发送的字节数（ _sendContentSize ）小于等于 文件总大小，
        //那么：按照输入的 需发送的字节数（ _sendContentSize ） 进行发送
        //否则：发送 文件大小 (fileSize) - 偏移（_fileOffset） 个字节
        if(_sendContentSize > 0 && _fileOffset + _sendContentSize <= fileSize ){
            _sendContentTrueSize = _sendContentSize;
        }
        else{
            if(fileSize <= _fileOffset){
                _sendContentTrueSize = 0;

                std::string err_msg = "http request file content parameter error. fileOffset/fileSize :"
                        + std::to_string(_fileOffset)
                        + "/"
                        + std::to_string(fileSize);

                MPLOG_ERROR << "HttpRequestFileContent::getContentLength :" << err_msg;
            }
            else{
                _sendContentTrueSize = fileSize - _fileOffset;
            }
        }
    }

    return _sendContentTrueSize;


}

//（如果返回Fasle表示数据存在异常）
bool HttpRequestFileContent::beginWriteData() {

    //设置未完成写入的文件大小
    _unreadSize = boost::lexical_cast<std::streamsize>(getContentLength()) ;

    //重置buf
    memset(_buf,'\0',MP::HTTP::READ_FILE_BUF_SIZE);


    if(!MP::FileUtils::check_file_isexist(_filePath)){
        MPLOG_ERROR << "HttpRequestFileContent : the file [ " << _filePath << " ] does not exist";
        return false;
    }

    if(!_read_file.is_open()){
        _read_file.open(_filePath,std::ios::in | std::ios::binary);

    }

    if(_read_file.is_open()){
        _read_file.seekg(_fileOffset,std::ios::beg);
        return true;
    }
    else{
        MPLOG_ERROR << "HttpRequestFileContent : the file [ " << _filePath << " ] open fail";
        return false;
    }
}

//如果返回真，则表示仍有数据需要写入；如果返回假，则表示当前数据写入完成后则Payload写入完毕
bool HttpRequestFileContent::onWriteDataSome(std::vector<boost::asio::const_buffer> & buffers) {

    //如果返回真，则表示仍有数据需要写入；如果返回假，则表示当前数据写入完成后则Payload写入完毕
    if(_read_file.is_open() && _read_file.good()){

        std::streamsize size = _unreadSize > MP::HTTP::READ_FILE_BUF_SIZE ? MP::HTTP::READ_FILE_BUF_SIZE : _unreadSize;
        _read_file.read(_buf,size);

        if(_read_file.gcount() == 0){
            //如果读取出来的数据未空，则返回假
            MPLOG_ERROR << "HttpRequestFileContent getContentDataSome empty. ";
            return false;
        }

        _unreadSize = _unreadSize - _read_file.gcount();
        buffers.push_back(boost::asio::buffer(_buf,_read_file.gcount()));

        return _unreadSize > 0;
    }
    else{
        return false;
    }
}

void HttpRequestFileContent::endWriteData(){
    _unreadSize = 0;

    //重置buf
    memset(_buf,'\0',MP::HTTP::READ_FILE_BUF_SIZE);

    if(_read_file.is_open()){
        _read_file.close();
    }
}

//void HttpRequestFileContent::onWrite(std::ostream & steam)  {

//    std::ifstream file(_filePath, std::ios::in | std::ios::binary);
//    if (!file){
//        return;
//    }

//    std::streamsize buf_size = 16384;       //16 * 1024;
//    char buf[buf_size];

//    file.seekg(_fileOffset,std::ios::beg);

//    std::streamsize unreadSize = boost::lexical_cast<std::streamsize>(_sendContentSize) ;
//    while (file.good()) {

//        file.read(buf, ((_sendContentSize == 0 || unreadSize > buf_size) ? buf_size : unreadSize));
//        //steam << buf;
//        steam.write(buf,file.gcount());
//        steam.flush();

//        unreadSize = unreadSize - file.gcount();
//        if(unreadSize <= 0){
//            break;
//        }
//    }

//    file.close();
//}

}   //INTERNAL
}   //HTTP
}   //MP
